/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.usfirst.frc2084.robotsimulator.hardware.crio;

import edu.wpi.first.wpilibj.AnalogModule;
import edu.wpi.first.wpilibj.DigitalModule;
import edu.wpi.first.wpilibj.Module;

/**
 *
 * @author Ben Wolsieffer
 */
public final class cRIO {

    private static Type TYPE = Type.I; // default to the cRIO I
    private final int numModules;
    private static cRIO instance;
    private static Module[] modules;

    public enum Type {

        I, II;
    }

    /**
     * Gets a singleton instance of the cRIO.
     *
     * @return the cRIO
     */
    public static cRIO getInstance() {
        if (instance == null) {
            instance = new cRIO(TYPE);
        }
        return instance;
    }

    public static void setType(Type type) {
        if (instance == null) {
            TYPE = type;
        } else {
            throw new IllegalStateException("cRIO already initialized");
        }
    }

    private cRIO(Type type) {
        switch (type) {
            case I:
                numModules = 8;
                break;
            case II:
                numModules = 4;
                break;
            default:
                numModules = 8;
        }
        modules = new Module[numModules];
    }

    public void add(Module module) {
//        int slot = module.getModuleNumber() - 1; // getModuleNumber() returns 1 or 2 -- not useful here
        int slot = getSlot(module);
        if (modules[slot] == null && slot < numModules) {
            modules[slot] = module;
        } else {
            throw new IllegalArgumentException("cRIO slot " + slot + " is already in use or is not on the cRIO");
        }
    }

    /**
     * Gets the module in the provided slot.
     *
     * @param slot The slot of the cRIO (1..8 or 1..4 depending on the type of
     * the cRIO.
     * @return
     */
    public Module getModule(int slot) {
        return modules[slot - 1];
    }

    public DigitalModule getDigitalModule(int moduleNumber) {
        if (moduleNumber == 1) {
            moduleNumber = 2;
        } else if (moduleNumber == 2) {
            if (TYPE == Type.I) {
                moduleNumber = 6;
            } else if (TYPE == Type.II) {
                moduleNumber = 4;
            }
        }
        if (modules[moduleNumber] instanceof DigitalModule) {
            return (DigitalModule) modules[moduleNumber];
        }
        throw new IllegalArgumentException("Module in slot is not a digital module.");
    }
    
    public AnalogModule getAnalogModule(int moduleNumber) {
        if (moduleNumber == 1) {
            moduleNumber = 1;
        } else if (moduleNumber == 2) {
            if (TYPE == Type.I) {
                moduleNumber = 5;
            } else if (TYPE == Type.II) {
                moduleNumber = 4;
            }
        }
        if (modules[moduleNumber] instanceof AnalogModule) {
            return (AnalogModule) modules[moduleNumber];
        }
        throw new IllegalArgumentException("Module in slot is not an analog module.");
        
    }
    
    /*
     * Gets the slot the given module is in.
     */
    private int getSlot(Module module) {
        return module.getModuleType().getValue() + 4 * (module.getModuleNumber() - 1);
    }
}
